from machine import Pin
from uart_lcd import UartLcd
from encoder import Encoder
from key_board import KeyBoard
from current_monitor import Current_Monitor
from main_power import Main_Power
import uasyncio as asyncio
import utime
class DeviceManager:

    # 屏幕功能界面
    SCREEN_VALUE = "VALUE"
    SCREEN_LINE = "LINE"
    SCREEN_PRESET = "PRESET"
    # 操作模式
    OPTMODE_NORMAL = "NORMAL"
    OPTMODE_PRESET = "PRESET"
    OPTMODE_ADJUST = "ADJUST"
    def __init__(self, lcd_tx, lcd_rx, encoder_a, encoder_b, endcoder_key, keyboard_slk, keyboard_dio,
                 IIC_SCL, IIC_SDA, power_ctl, power_tx, power_rx):
        self.last_presskey = ""
        self.key_press_list = []
        asyncio.create_task(self.loop_clear_keypress())
        self.OUT_ACT_INDEX = 2
        self.LCD_SCREEN = self.SCREEN_VALUE
        self.OPT_MODE = self.OPTMODE_NORMAL
        self.lcd = self._init_lcd(lcd_tx, lcd_rx, self.lcd_callback)
        self.encoder = self._init_encoder(a_channel=encoder_a, b_channel=encoder_b, key_channel=endcoder_key,
                                          init_val=0, callback=self.encoder_callback)
        self.keyboard = self._init_key_board(keyboard_slk, keyboard_dio, self.key_press_callback)
        self.current_monitor = self._init_Current_Monitor(IIC_SCL, IIC_SDA, self.current_callabck)
        self.main_power = self._init_main_power(power_ctl, power_tx, power_rx, self.power_status_callback)

    def _init_lcd(self, lcd_tx, lcd_rx, callback=None):
        lcd = UartLcd(lcd_tx, lcd_rx)
#         lcd.show_voltage(12)
#         lcd.show_current(1)
#         lcd.show_power(12, 1)
        return lcd

    def _init_encoder(self, a_channel, b_channel, key_channel, init_val, div=4, val_min=0, val_max=100, callback=None):
        pin_a = Pin(a_channel, Pin.IN, Pin.PULL_UP)
        pin_b = Pin(b_channel, Pin.IN, Pin.PULL_UP)
        pin_key = Pin(key_channel, Pin.IN, Pin.PULL_UP)
        return Encoder(pin_a, pin_b, pin_key, v=init_val, div=div, vmin=val_min, vmax=val_max, callback=callback,
                       key_cb=self.encoder_key_callback)

    def _init_Current_Monitor(self, IIC_SCL, IIC_SDA, current_callback):
        return Current_Monitor(IIC_SCL, IIC_SDA, current_callback)

    def _init_main_power(self, power_ctl, power_tx, power_rx, power_status_callback):
        return Main_Power(power_ctl, power_tx, power_rx, power_status_callback)

    def _init_key_board(self, slk, dio, key_callback):
        
        return KeyBoard(slk, dio, key_callback)
    
    def power_status_callback(self, data):
        # print("time---->", utime.time())
        # data.show_status()
        self.update_Bottom_Out_Info(2, data.pwr_vout, data.pwr_iout, data.pwr_cvcc, data.pwr_onoff)
        preset = self.main_power.presets[data.pwr_extact_m]
        if self.OUT_ACT_INDEX == 2:
            self.update_main_screen_value(self.OUT_ACT_INDEX, data.pwr_vout, data.pwr_iout, data.pwr_power,
                data.pwr_protect, data.pwr_cvcc, data.pwr_lock, data.pwr_onoff, data.pwr_uin, data.pwr_t_in,
                str(data.pwr_out_h) + ":" + str(data.pwr_out_m) + ":" + str(data.pwr_out_s),
                data.pwr_ah, data.pwr_wh, data.pwr_extact_m, preset.s_ovp, preset.s_ocp, preset.s_opp)

    def update_Bottom_Out_Info(self, out_index, vout, iout, left_info, right_info):
        if out_index == 2:
            self.lcd.show_curr_Adj_left(iout)
            self.lcd.show_curr_Adj_right(iout)
            self.lcd.show_curr_Adj_info_cvcc(left_info)
            self.lcd.show_curr_Adj_info_onoff(right_info)
        elif out_index == 0:
            self.lcd.show_curr_33(round(iout, 2))
            self.lcd.show_curr_33_info("CV:ON")
        elif out_index == 1:
            self.lcd.show_curr_A5(round(iout, 2))
            self.lcd.show_curr_A5_info("CV:ON")
        elif out_index == 3:
            self.lcd.show_curr_A12(round(iout, 2))
            self.lcd.show_curr_A12_info("CV:ON")
        elif out_index == 4:
            self.lcd.show_curr_S12(round(iout, 2))
            self.lcd.show_curr_S12_info("CV:ON")


    def update_main_screen_value(self, out_index, vout, iout, power, status, cvcc="CV", key_lock=False, out_onoff="ON",
                                     uin=0.00, temp_inside=0.00, open_time="00:00:00", out_ah=0, out_wh=0,
                                     mode_index=-1, ovp=0.00, ocp=0.00, opp=0.00):
        print("update screen value:", out_index, vout, iout, power, status, ovp, ocp, opp)
        if out_index == 2:
            # main left
            self.lcd.show_voltage(vout)
            self.lcd.show_current(iout)
            self.lcd.show_power(power)
            # main left preset info
            self.lcd.show_voltage_info("|---" + str(ovp) + "---|")
            self.lcd.show_current_info("|---" + str(ocp) + "---|")
            self.lcd.show_power_info("|---" + str(opp) + "---|")
            # status
            self.lcd.show_state_txt1("[-" + status + "]")
            self.lcd.show_state_txt2("[-" + cvcc + "-]")
            if key_lock:
                self.lcd.show_state_txt3("[LOCK]")
            else:
                self.lcd.show_state_txt3("[UNLK]")
            if out_onoff == "ON":
                self.lcd.show_state_txt4("[-ON-]")
            else:
                self.lcd.show_state_txt4("[-OFF]")
            # right info
            self.lcd.show_info_txt0("input:" + str(uin) + "V")
            self.lcd.show_info_txt2("temp :" + str(temp_inside) + "C")
            self.lcd.show_info_txt4("time :" + open_time)
            self.lcd.show_info_txt6("out:" + str(out_ah) + "mAH")
            self.lcd.show_info_txt8("out:" + str(out_wh) + "mWH")
            # preset index
            self.lcd.show_mode_index(mode_index)
        else:
            # main left
            self.lcd.show_voltage(vout)
            self.lcd.show_current(iout)
            self.lcd.show_power(power)
            # main left preset info
            self.lcd.show_voltage_info("|---" + str(ovp) + "---|")
            self.lcd.show_current_info("|---" + str(ocp) + "---|")
            self.lcd.show_power_info("|---" + str(opp) + "---|")
            # status
            self.lcd.show_state_txt1("[-RUN]")
            self.lcd.show_state_txt2("[-CV-]")
            self.lcd.show_state_txt3("[UNLK]")
            self.lcd.show_state_txt4("[-ON-]")
            # right info
            self.lcd.show_info_txt0("input:" + str(vout) + "V")
            self.lcd.show_info_txt2("//////////////////////")
            self.lcd.show_info_txt4("//////////////////////")
            self.lcd.show_info_txt6("//////////////////////")
            self.lcd.show_info_txt8("//////////////////////")
            # preset index
            self.lcd.show_mode_index(mode_index)


    def encoder_callback(self, pos, delta):
        print("encoder_callback.pos:", pos, " delta:", delta)

    def encoder_key_callback(self):
        print("encoder_key_pressed_callback.")

    def lcd_callback(self, data):
        print("lcd_callback.data:", data)
        
    def key_press_callback(self, key_name):
        if (key_name == self.last_presskey):
            return 
        self.last_presskey = key_name
        print(f"{key_name} pressed!")
        self.key_press_list.append(key_name)

    def current_callabck(self, curr_data):
#        print("curr data:", curr_data)
#         {'monitor_+12V': -0.1951219, 'monitor_+5V': -0.09756097, 'monitor_+3V3': -0.09756097}
        if 'monitor_+3V3' in curr_data:
            iout = round(curr_data['monitor_+3V3'], 2)
            self.update_Bottom_Out_Info(0, 3.30, iout, "CV", "ON")
            if self.OUT_ACT_INDEX == 0:
                self.update_main_screen_value(out_index=0, vout=3.30, iout=iout, power=round(3.30 * iout, 2),
                                          status="RUN", ovp=3.30, ocp=3.00, opp=9.90)
        if 'monitor_+5V' in curr_data:
            iout = round(curr_data['monitor_+5V'], 2)
            self.update_Bottom_Out_Info(1, 5.00, iout, "CV", "ON")
            if self.OUT_ACT_INDEX == 1:
                self.update_main_screen_value(out_index=1, vout=5.00, iout=iout, power=round(5.00 * iout, 2),
                                          status="RUN", ovp=5.00, ocp=3.00, opp=15.00)
        if 'monitor_+12V' in curr_data:
            iout = round(curr_data['monitor_+12V'], 2)
            self.update_Bottom_Out_Info(3, 12.00, iout, "CV", "ON")
            if self.OUT_ACT_INDEX == 3:
                self.update_main_screen_value(out_index=3, vout=12.00, iout=iout, power=round(12.00 * iout, 2),
                                          status="RUN", ovp=12.00, ocp=3.00, opp=36.00)
        if 'monitor_-12V' in curr_data:
            iout = round(curr_data['monitor_-12V'], 2)
            self.update_Bottom_Out_Info(4, -12.00, iout, "CV", "ON")
            if self.OUT_ACT_INDEX == 4:
                self.update_main_screen_value(out_index=4, vout=-12.00, iout=iout, power=round(12.00 * iout, 2),
                                          status="RUN", ovp=12.00, ocp=0.5, opp=6.00)

        
    async def loop_clear_keypress(self):
        """
        按键消抖,1秒内重复按无效。一秒后清除last key后可以重复按。
        """
        while True:
            try:
                # todo clear last keypress event
                self.last_presskey = ""
                while len(self.key_press_list):
                    # print("process key pressed event.", self.key_press_list)
                    ke = self.key_press_list.pop()
                    print("process key event:", ke)
                    self.key_press_process(ke)
                
            except Exception as e:
                print("loop_clear_keypress error:", e)
            await asyncio.sleep(1)
    
    def key_press_process(self, key_name):
        """
        key press process method invoke.
        """
        print("key_press_process, key:", key_name)
        if key_name == "KEY_POWER":
            self.main_power.turn_main_power()
            mp_st = self.main_power.get_main_power_status()
            print("main power status:", mp_st)
            if mp_st:
                self.keyboard.change_led_mode("power", "static", True)
            else:
                self.keyboard.change_led_mode("power", "flash", False )
        elif key_name == "KEY_UP":
            if self.OPT_MODE == self.OPTMODE_NORMAL:
                self.OUT_ACT_INDEX = self.OUT_ACT_INDEX + 1
                if self.OUT_ACT_INDEX < 0:
                    self.OUT_ACT_INDEX = 0
                if self.OUT_ACT_INDEX > 4:
                    self.OUT_ACT_INDEX = 4
                self.lcd.show_out_activate_index(self.OUT_ACT_INDEX)
        elif key_name == "KEY_DOWN":
            if self.OPT_MODE == self.OPTMODE_NORMAL:
                self.OUT_ACT_INDEX = self.OUT_ACT_INDEX - 1
                if self.OUT_ACT_INDEX < 0:
                    self.OUT_ACT_INDEX = 0
                if self.OUT_ACT_INDEX > 4:
                    self.OUT_ACT_INDEX = 4
                self.lcd.show_out_activate_index(self.OUT_ACT_INDEX)
        elif key_name == "KEY_MODE":
            if self.LCD_SCREEN == self.SCREEN_VALUE:
                self.LCD_SCREEN = self.SCREEN_PRESET
            elif self.LCD_SCREEN == self.SCREEN_PRESET:
                self.LCD_SCREEN = self.SCREEN_VALUE
            elif self.LCD_SCREEN == self.SCREEN_LINE:
                self.LCD_SCREEN = self.SCREEN_PRESET
        elif key_name == "KEY_SET":
            pass
        elif key_name == "KEY_LIGHT":
            if self.LCD_SCREEN == self.SCREEN_VALUE:
                self.LCD_SCREEN = self.SCREEN_LINE
            elif self.LCD_SCREEN == self.SCREEN_PRESET:
                self.LCD_SCREEN = self.SCREEN_LINE
            elif self.LCD_SCREEN == self.SCREEN_LINE:
                self.LCD_SCREEN = self.SCREEN_VALUE
            